#ifndef TOOLS_VECTOR_H_
#define TOOLS_VECTOR_H_

#include<stdlib.h>
#include<string.h>

#include<tools/lb_memory.h>

#ifdef __cplusplus
extern "C"{
#endif

// copy_data vec2的数据拷贝到vec1
//
#define LB_VECTOR_FUNC_DECLARE(typevalue) typedef struct LB_Vector_##typevalue \
{\
    typevalue data[200];\
    typevalue* extra_data;\
    unsigned int extra_data_size;\
    unsigned int size;\
    typevalue * (*at)(struct LB_Vector_##typevalue*, int);\
    int (*push_back)(struct LB_Vector_##typevalue*, typevalue);\
    int (*find)(struct LB_Vector_##typevalue*,typevalue);\
    struct LB_Vector_##typevalue (*intersection)(struct LB_Vector_##typevalue*,struct LB_Vector_##typevalue*);\
    void (*clear)(struct LB_Vector_##typevalue*);\
    void (*resize)(struct LB_Vector_##typevalue*, int);\
    void (*copy_data)(struct LB_Vector_##typevalue*,struct LB_Vector_##typevalue*);\
    typevalue (*pop)(struct LB_Vector_##typevalue*);\
}LB_Vector_##typevalue;\
void lb_vector_init_##typevalue(struct LB_Vector_##typevalue*);\


#define LB_VECTOR_FUNC(typevalue)  static  typevalue * lb_vector_at_##typevalue(\
LB_Vector_##typevalue* vec,int i)\
{\
    if(i<0||i>=vec->size){return NULL;}\
    else if(vec->extra_data==NULL){return &(vec->data[i]);}\
    else{return &(vec->extra_data[i]);}\
}\
static int  lb_vector_push_back_##typevalue(\
    LB_Vector_##typevalue* vec, typevalue v)\
{\
    if(vec->extra_data==NULL)\
    {\
        if(vec->size<200){\
            vec->data[vec->size]=v;vec->size++;\
        }\
        else{\
            vec->extra_data=(typevalue*)malloc(sizeof(typevalue)*vec->size*3);\
            vec->extra_data_size=vec->size*3;\
            memmove(vec->extra_data,vec->data,sizeof(typevalue)*200);\
            vec->extra_data[vec->size]=v;vec->size++;\
        }\
    }\
    else\
    {\
        if(vec->size>=vec->extra_data_size){\
            vec->extra_data=(typevalue*)realloc(vec->extra_data, sizeof(typevalue)*(vec->size*3));\
            vec->extra_data_size=vec->size*3;\
        }\
        vec->extra_data[vec->size]=v;vec->size++;\
    }\
    return 1; \
}\
static void lb_vector_clear_##typevalue(\
    LB_Vector_##typevalue* vec)\
{\
    if(vec->extra_data!=NULL){free(vec->extra_data);vec->extra_data=NULL;}\
    vec->size=0;\
    vec->extra_data_size=0;\
}\
static void  lb_vector_resize_##typevalue(struct LB_Vector_##typevalue* vec, int size)\
{\
    if(size<0){return;}\
    if(vec->extra_data==NULL)\
    {\
        if(size>200)\
        {\
            vec->extra_data=(typevalue*)malloc(sizeof(typevalue)*(size+20) );\
            vec->extra_data_size=size+20;\
            memmove(vec->extra_data,vec->data,sizeof(typevalue)*vec->size);\
        }\
    }\
    else if(size>vec->extra_data_size)\
    {\
        vec->extra_data = (typevalue*)realloc(vec->extra_data, sizeof(typevalue)*(size+20) );\
        vec->extra_data_size=size+20;\
    }\
    vec->size=size;\
}\
static typevalue lb_vector_pop_##typevalue(struct LB_Vector_##typevalue*vec)\
{\
    if(vec->extra_data==NULL)\
    {\
        vec->size--;\
        return vec->data[vec->size];\
    }\
    vec->size--;\
    return vec->extra_data[vec->size];\
}\
static void lb_vector_copy_data_##typevalue(struct LB_Vector_##typevalue*vec1,\
    struct LB_Vector_##typevalue* vec2)\
{\
    lb_vector_resize_##typevalue(vec1,vec2->size);\
    memmove((vec1->extra_data==NULL?vec1->data:vec1->extra_data),\
        (vec2->extra_data==NULL?vec2->data:vec2->extra_data),sizeof(typevalue)*vec2->size);\
}\
static inline int lb_vector_find_##typevalue(struct LB_Vector_##typevalue*vec,\
    typevalue v)\
{\
    for(int i=0;i<vec->size;i++)\
    {\
        if( *(lb_vector_at_##typevalue(vec,i))==v)\
        {\
            return i;\
        }\
    }\
    return  -1;\
}\
struct LB_Vector_##typevalue lb_vector_intersection_##typevalue(\
    struct LB_Vector_##typevalue*vec1,struct LB_Vector_##typevalue*vec2)\
{\
    struct LB_Vector_##typevalue vec;\
    lb_vector_init_##typevalue(&vec);\
    for(int i=0;i<vec1->size;i++)\
    {\
        typevalue v = *(lb_vector_at_##typevalue(vec1,i));\
        if(lb_vector_find_##typevalue(vec2,v)!=-1)\
        {\
            lb_vector_push_back_##typevalue(&vec,v);\
        }\
    }\
    return vec;\
}\
void lb_vector_init_##typevalue(struct LB_Vector_##typevalue *vec)\
{\
    vec->extra_data_size=0;\
    vec->extra_data=NULL;\
    vec->size=0;\
    vec->at=lb_vector_at_##typevalue;\
    vec->push_back=lb_vector_push_back_##typevalue;\
    vec->clear=lb_vector_clear_##typevalue;\
    vec->resize=lb_vector_resize_##typevalue;\
    vec->pop=lb_vector_pop_##typevalue;\
    vec->copy_data  =lb_vector_copy_data_##typevalue;\
    vec->find=lb_vector_find_##typevalue;\
    vec->intersection=lb_vector_intersection_##typevalue;\
}\

// LB_Vector_voidptr


// lb_vector1的resize保留原数据
//
#define LB_VECTOR1_FUNC_DECLARE(typevalue) typedef struct LB_Vector1_##typevalue \
{\
    typevalue* extra_data;\
    unsigned int extra_data_size;\
    unsigned int size;\
}LB_Vector1_##typevalue;\
static inline void lb_vector1_init_##typevalue(struct LB_Vector1_##typevalue* vec)\
{\
    vec->extra_data_size=0;\
    vec->extra_data=NULL;\
    vec->size=0;\
}\
static inline  typevalue * lb_vector1_at_##typevalue(\
LB_Vector1_##typevalue* vec,int i)\
{\
    if(i<0||i>=vec->size){return NULL;}\
    else{return &(vec->extra_data[i]);}\
}\
static inline int  lb_vector1_pushback_##typevalue(\
    LB_Vector1_##typevalue* vec, typevalue v)\
{\
    if(vec->extra_data==NULL)\
    {\
        vec->size=0;\
        vec->extra_data=(typevalue*)malloc(sizeof(typevalue)*2);\
        vec->extra_data_size=2;\
    }\
    else if(vec->size>=vec->extra_data_size)\
    {\
        vec->extra_data=(typevalue*)realloc(vec->extra_data, sizeof(typevalue)*(vec->size*2));\
        vec->extra_data_size=vec->size*2;\
    }\
    vec->extra_data[vec->size]=v;vec->size++;\
    return 1; \
}\
static inline void lb_vector1_clear_##typevalue(\
    LB_Vector1_##typevalue* vec)\
{\
    if(vec->extra_data!=NULL){free(vec->extra_data);vec->extra_data=NULL;}\
    vec->size=0;\
    vec->extra_data_size=0;\
}\
static inline void  lb_vector1_resize_##typevalue(struct LB_Vector1_##typevalue* vec, int size)\
{\
    if(size<0){return;}\
    vec->extra_data=(typevalue*)realloc(vec->extra_data,sizeof(typevalue)*(size) );\
    vec->extra_data_size=size;\
    vec->size=size;\
}\
static inline typevalue lb_vector1_pop_##typevalue(struct LB_Vector1_##typevalue*vec)\
{\
    vec->size--;\
    return vec->extra_data[vec->size];\
}\
static inline void lb_vector1_copy_data_##typevalue(struct LB_Vector1_##typevalue*vec1,\
    struct LB_Vector1_##typevalue* vec2)\
{\
    lb_vector1_resize_##typevalue(vec1,vec2->size);\
    memmove((vec1->extra_data),\
        (vec2->extra_data),sizeof(typevalue)*vec2->size);\
}\
static inline int lb_vector1_find_##typevalue(struct LB_Vector1_##typevalue*vec,\
    typevalue v)\
{\
    for(int i=0;i<vec->size;i++)\
    {\
        if(vec->extra_data[i]==v)\
        {\
            return i;\
        }\
    }\
    return  -1;\
}\
static inline void lb_vector1_remove_##typevalue(LB_Vector1_voidptr *vec,typevalue v)\
{\
    for(int i=0;i<vec->size;i++)\
    {\
        if(vec->extra_data[i] ==v )\
        {\
            vec->size--;\
            vec->extra_data[i]= vec->extra_data[vec->size];\
            break;\
        }\
    }\
}\










typedef void* voidptr;


LB_VECTOR_FUNC_DECLARE(voidptr)

// LB_Matrix *lb_matrix_mult_##typevalue(

LB_VECTOR_FUNC_DECLARE(int)


LB_VECTOR1_FUNC_DECLARE(voidptr)



#ifdef __cplusplus
}
#endif
#endif
